#include <exception>
#include "Cvars.h"

using std::exception;

CvarSystem::CvarSysPtr CvarSystem::_instance(new CvarSystem());
CvarSystem::CvarMap CvarSystem::_cvars;

CvarSystem& CvarSystem::getInstance()
{
	return *(_instance);
}

CvarPtr CvarSystem::getCvar(const string& name, bool createIfNotExists)
{
	CvarMap::iterator it = _cvars.find(name);
	if (it == _cvars.end()) {
		if (!createIfNotExists)
			throw exception("invalid key");
		else
			return addCvarInternal(name, 0, false);
	}		

	return it->second;
}

CvarPtr CvarSystem::addCvar(const string& name, int defaultValue)
{
	return addCvarInternal(name, defaultValue, true);
}

CvarPtr CvarSystem::addCvar(const string& name, float defaultValue)
{
	return addCvarInternal(name, defaultValue, true);
}

CvarPtr CvarSystem::addCvar(const string& name, bool defaultValue)
{
	return addCvarInternal(name, defaultValue, true);
}

CvarPtr CvarSystem::addCvar(const string& name, char* defaultValue)
{
	return addCvarInternal(name, defaultValue, true);
}

template <typename T>
static CvarPtr CvarSystem::addCvarInternal(const string& name, T defaultValue, bool set)
{
	CvarMap::iterator it = _cvars.find(name);

	CvarPtr cvar;
	if (it == _cvars.end()) {
		cvar = CvarPtr(new Cvar(defaultValue));		
		_cvars[name] = cvar;		
	}
	else {
		cvar = it->second;
	}

	if (set && !(cvar->_set)) {
		it->second->_ivalue = *(reinterpret_cast<int*>(&defaultValue));
	}

	cvar->_set = set;

	return cvar;
}